package com.util.boxs;

import com.util.boxs.bodys.BaseBody;
import org.jbox2d.callbacks.QueryCallback;
import org.jbox2d.collision.AABB;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.Fixture;
import org.jbox2d.dynamics.World;
import org.jbox2d.dynamics.contacts.Contact;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Box2d基类
 */
public class BoxWorld{
    private static World world;
    protected static Map<Body, BaseBody> allBody = new ConcurrentHashMap<>();
    private static final float RATE = 6f;//box2d世界与屏幕像素分辨率的比例
    private static final float TIME_STEP = 1f/20f;//box2d世界刷新频率
    private static int WIDTH;//屏幕分辨率宽度
    private static int HEIGHT;//屏幕分辨率高度
    private static AABB worldBound;//世界边界
    public BoxWorld(){
        if(world==null) {
            throw new RuntimeException("世界必须被初始化。需要在使用前调用且仅调用一次静态方法init(int,int)");
        }
    }

    protected static Body create(BodyDef bodyDef,BaseBody body){
        Body b = world.createBody(bodyDef);
        allBody.put(b,body);
        return b;
    }

    public static void remove(BaseBody body){
        allBody.remove(body.getBody());
        world.destroyBody(body.getBody());
    }

    /**
     * 初始化世界，同时指定屏幕分辨率的宽高
     * @param pixelWidth
     * @param pixelHeight
     */
    public static void init(int pixelWidth,int pixelHeight){
        WIDTH = pixelWidth;
        HEIGHT = pixelHeight;
        world = new World(new Vec2(0,-10));
        worldBound = new AABB(getPixel2MileVec2(0,0),getPixel2MileVec2(pixelWidth,pixelHeight));
    }
    public static World getWorld(){
        return world;
    }
    public static int mile2Pixel(float mile){
        return (int)(mile*RATE);
    }

    public static float pixel2Mile(int pixel){
        return pixel/RATE;
    }

    public static int toPixelHeight(float mile){
        return HEIGHT - (int) (mile*RATE);
    }

    public static float pixel2Height(int height){
        return (HEIGHT - height)/RATE;
    }

    public static Vec2 getPixel2MileVec2(int x,int y){
        return new Vec2(pixel2Mile(x),pixel2Mile(y));
    }

    public static void step(){
        world.step(TIME_STEP,8,8);
    }

    public static void queryBody(HitCallBack callBack,int pixelX,int pixelY){
        Vec2 vec2 = getPixel2MileVec2(pixelX,pixelY);
        AABB aabb = new AABB();
        aabb.lowerBound.set(vec2.x-0.001f,vec2.y-0.001f);
        aabb.upperBound.set(vec2.x+0.001f,vec2.y+0.001f);
        world.queryAABB(new QueryCallback() {
            @Override
            public boolean reportFixture(Fixture fixture) {
                return callBack.reportBody(allBody.get(fixture.m_body));
            }
        },aabb);
    }

    public static boolean isOutOfWorld(Body body){
        return !AABB.testOverlap(worldBound,body.getFixtureList().getAABB(0));
    }
}
